<template>
  <section>
    <Header title="个税计算器" />
    <!-- 个税计算器 -->
    <div class="tax-wrap">
      <el-form ref="form" :model="form" label-width="100px" class="tax-form">
        <el-form-item label="当前月份">
          <el-select v-model="form.month" placeholder="请选择">
            <el-option v-for="m in 12" :key="m" :label="`${m}月`" :value="m" />
          </el-select>
        </el-form-item>
        <el-form-item label="月固定薪资">
          <el-input v-model="form.pay" placeholder="请输入" />
        </el-form-item>
        <el-form-item label="月基础免税">
          <el-input v-model="form.deductBase" placeholder="请输入" />
        </el-form-item>
        <el-form-item label="奖金扣款">
          <el-input
            v-for="(m, dx) in form.extData"
            :key="dx"
            v-model="form.extData[dx]"
            :placeholder="`请输入${dx+1}月奖金扣款之和`"
          >
            <template slot="prepend">{{`0${dx+1}`.substr(-2)}}月</template>
          </el-input>
        </el-form-item>
        <el-form-item label="五险-医疗险">
          <el-input v-model="form.deductBonus.medical.rate" placeholder="请输入">
            <template slot="prepend">个人比例</template>
            <template slot="append">%</template>
          </el-input>
          <el-input v-model="form.deductBonus.medical.fBase" placeholder="请输入">
            <template slot="prepend">上半年基数</template>
          </el-input>
          <el-input v-model="form.deductBonus.medical.sBase" placeholder="请输入">
            <template slot="prepend">下半年基数</template>
          </el-input>
        </el-form-item>
        <el-form-item label="五险-养老险">
          <el-input v-model="form.deductBonus.retired.rate" placeholder="请输入">
            <template slot="prepend">个人比例</template>
            <template slot="append">%</template>
          </el-input>
          <el-input v-model="form.deductBonus.retired.fBase" placeholder="请输入">
            <template slot="prepend">上半年基数</template>
          </el-input>
          <el-input v-model="form.deductBonus.retired.sBase" placeholder="请输入">
            <template slot="prepend">下半年基数</template>
          </el-input>
        </el-form-item>
        <el-form-item label="五险-失业险">
          <el-input v-model="form.deductBonus.unemploy.rate" placeholder="请输入">
            <template slot="prepend">个人比例</template>
            <template slot="append">%</template>
          </el-input>
          <el-input v-model="form.deductBonus.unemploy.fBase" placeholder="请输入">
            <template slot="prepend">上半年基数</template>
          </el-input>
          <el-input v-model="form.deductBonus.unemploy.sBase" placeholder="请输入">
            <template slot="prepend">下半年基数</template>
          </el-input>
        </el-form-item>
        <el-form-item label="一金-公积金">
          <el-input v-model="form.deductBonus.gjj.rate" placeholder="请输入">
            <template slot="prepend">个人比例</template>
            <template slot="append">%</template>
          </el-input>
          <el-input v-model="form.deductBonus.gjj.fBase" placeholder="请输入">
            <template slot="prepend">上半年基数</template>
          </el-input>
          <el-input v-model="form.deductBonus.gjj.sBase" placeholder="请输入">
            <template slot="prepend">下半年基数</template>
          </el-input>
        </el-form-item>
        <el-form-item label="专项计入">
          <el-switch v-model="form.deductSpecIn"></el-switch>
        </el-form-item>
        <!-- 这里可以优化-新增、删除，选择某一个专项 -->
        <el-form-item label="专项-房贷">
          <el-input v-model="form.deductSpec.house.deduct" placeholder="请输入">
            <template slot="prepend">扣除数</template>
          </el-input>
          <el-input v-model="form.deductSpec.house.start" placeholder="请输入">
            <template slot="prepend">起抵月</template>
          </el-input>
        </el-form-item>
        <el-form-item label="专项-父亲">
          <el-input v-model="form.deductSpec.father.deduct" placeholder="请输入">
            <template slot="prepend">扣除数</template>
          </el-input>
          <el-input v-model="form.deductSpec.father.start" placeholder="请输入">
            <template slot="prepend">起抵月</template>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onCalculator">立即计算</el-button>
        </el-form-item>
      </el-form>

      <!-- result -->
      <div v-if="resultObj.sumupListData.length" class="tax-result">
        <el-table :data="resultObj.sumupListData" border class="tax-table">
          <el-table-column prop="month" label="月份" align="center" :formatter="formatMonth" class-name="weight"></el-table-column>
          <el-table-column prop="pay" label="月薪" align="center"></el-table-column>
          <el-table-column prop="paySum" label="累计收入" align="center"></el-table-column>
          <el-table-column prop="deductBase" label="起征金" align="center"></el-table-column>
          <el-table-column prop="gjj" label="公积金" align="center"></el-table-column>
          <el-table-column prop="medical" label="医疗" align="center"></el-table-column>
          <el-table-column prop="retired" label="养老" align="center"></el-table-column>
          <el-table-column prop="unemploy" label="失业" align="center"></el-table-column>
          <el-table-column prop="deductBonus" label="五险一金" align="center"></el-table-column>
          <el-table-column prop="house" label="租房" align="center"></el-table-column>
          <el-table-column prop="father" label="养父" align="center"></el-table-column>
          <el-table-column prop="deductSpec" label="专项合计" align="center"></el-table-column>
          <el-table-column prop="all" label="总计免税" align="center"></el-table-column>
          <el-table-column prop="needTaxSum" label="累计应纳税" align="center"></el-table-column>
          <el-table-column prop="tax" label="纳税" align="center"></el-table-column>
          <el-table-column prop="taxSum" label="累计纳税" align="center"></el-table-column>
          <el-table-column prop="cash" label="到手" align="center"></el-table-column>
        </el-table>
        <p v-for="(desc, idx) in explain" :key="idx" class="desc">{{ idx + 1 }}: {{ desc }}</p>
        <p class="desc">Cash总金额: {{ +resultObj.cashSum.toFixed(2) }}</p>
      </div>
    </div>
  </section>
</template>
<script>
import { Header } from '@/components'
export default {
  name: 'TAX',
  components: { Header },
  data () {
    /** rate 指的百分数，需除以100 */
    return {
      taxRate: [ // 税率
        {
          rate: 3,
          deduct: 0,
          min: 0,
          max: 36000
        },
        {
          rate: 10,
          deduct: 2520,
          min: 36000,
          max: 144000
        },
        {
          rate: 20,
          deduct: 16920,
          min: 144000,
          max: 300000
        },
        {
          rate: 25,
          deduct: 31920,
          min: 300000,
          max: 420000
        },
        {
          rate: 30,
          deduct: 52920,
          min: 420000,
          max: 660000
        },
        {
          rate: 35,
          deduct: 85920,
          min: 660000,
          max: 960000
        },
        {
          rate: 45,
          deduct: 181920,
          min: 960000,
          max: Infinity
        }
      ],
      form: {
        pay: 31000, // 月薪
        deductBase: 5000, // 月免税额
        month: new Date().getMonth(), // 当前月份
        deductBonus: { // 五险一金
          unemploy: {
            label: '失业',
            rate: 0.3,
            fBase: 2360,
            sBase: 2360
          },
          medical: {
            label: '医疗',
            rate: 2,
            fBase: 38892, // 缴纳基数-上半年
            tBase: 33659, // 缴纳基数-789月
            sBase: 30615 // 缴纳基数-下半年
          },
          retired: {
            label: '养老',
            rate: 8,
            fBase: 24930,
            sBase: 26421
          },
          gjj: {
            label: '公积金',
            rate: 6,
            fBase: 38892,
            sBase: 33659
          }
        },
        deductSpecIn: false, // 专项附加计入免税统计====扣税方式申报的时候选择扣缴义务人申报(公司)，不要选自行申报
        deductSpec: { // 专项附加
          house: {
            label: '房租',
            start: 1, // 起始月份
            deduct: 1500 // 扣除数
          },
          father: {
            label: '父亲60',
            start: 11,
            deduct: 1500
          }
        },
        extData: [-281.82, 0, 100, 0, 0, 0, 460, 0, 0, 0, 0, 0], // 额外计税值
      },
      resultObj: {},
      explain: [
        '次月发放上月工资，工资条上显示的个税扣除数为下一个月的个税（因为在下一个计税周期计算发放）。',
        '比如：2022年12月的工资条，个税其实是2023年1月的个税金额，2023.1月工资条的个税是2023.2月计算出来的值，以此类推。',
        '个税App上显示的是当月的个税，所以个税App上跟公司的工资条显示不一致。'
      ]
    }
  },
  computed: {
    // 全年免税总额
    deductAllSum: function () {
      const _r = this.resultObj
      return _r.deductBaseSum + _r.deductSpecSum + _r.deductBonusSum
    }
  },
  created () {
    this.resultInit()
  },
  methods: {
    /** 结果数据初始化 */
    resultInit () {
      this.resultObj = {
        paySum: 0, // 月薪总额
        deductBaseSum: 0, // 免税额扣除总额-5000基数
        deductSpecSum: 0, // 专项附加扣除总额-赡养、教育、养育、房贷等
        deductBonusSum: 0, // 五险一金扣除总额
        sumupListData: [], // 统计表格数据====展示数据集
        taxPaySum: 0, // 累计已预扣预缴税额-总计已缴的税额
        taxNeedPaySum: 0,// 累计预扣预缴应纳税所得额-总计需要交税的金额
        taxTargetSumList: [], // 每个月需要纳税所得额
        taxPaySumupList: [], // 每个月交税额
        cashSum: 0 // 到手现金
      }
    },
    // 个税计算处理
    onCalculator () {
      this.resultInit()
      this.taxDeductSumup(this.form.month)
    },
    formatMonth (row) {
      return `${row.month}月`
    },
    /**
     * 扣税减免
     * m: 月份
     */
    taxDeductSumup (m) {
      for (let i = 1; i < m+1; i++) {
        // 当月数据对象
        const _curM = {
          month: i,
          pay: +this.form.pay + (this.form.extData[i-1]),
          deductBase: +this.form.deductBase
        }
        // 当月免税扣除总额
        let _deductSum = 0

        // 获取五险一金单项数据&总计
        const { curMBonus, curMSumBonus } = this.taxDeductBonus(i, _curM)
        Object.assign(_curM, curMBonus)
        _deductSum += +curMSumBonus.toFixed(2)
        this.resultObj.deductBonusSum += +curMSumBonus.toFixed(2)

        // 获取专项附加单项数据&总计
        const { curMSpec, curMSumSpec } = this.taxDeductSpec(i, _curM)
        Object.assign(_curM, curMSpec)
        _deductSum += curMSumSpec
        this.resultObj.deductSpecSum += curMSumSpec

        // 月免税额
        _deductSum += _curM.deductBase
        this.resultObj.deductBaseSum += _curM.deductBase

        _curM.all = _deductSum.toFixed(2)
        this.resultObj.sumupListData.push(_curM)
      }

      // 重中之重-月交税数据&总计
      this.taxSubmitMonth(m)
    },
    /**
     * 月交税计算-金额写入
     * m: 月份
     * 1. 一年分成12个月，交纳税也分为12期
     * 2. 本期应预扣预缴税额 = （累计预扣预缴应纳税所得额 * 税率 - 速算扣除数）- 累计已预扣预缴税额
     * 3. 累计预扣预缴应纳税所得额 = 累计收入 - 累计免税收入 - 累计减除费用 - 累计专项扣除 - 累计专项附加扣除 -  累计依法确定的其他扣除
     * 4. 其中，累计减除费用，按照5000元/月乘以纳税人当年截至本月在本单位的任职受雇月份数计算
     */
    taxSubmitMonth (m) {
      for (let i = 1; i < m+1; i++) {
        const _incomePay  = +this.sumupIncome(i)
        const _deductPay = +this.deductIncome(i)
        // 累计预扣预缴应纳税所得额
        const _needPayAccount = +(_incomePay - _deductPay).toFixed(2)
        this.resultObj.taxTargetSumList.push(+_needPayAccount)

        // 累计收入写到表格
        this.$set(this.resultObj?.sumupListData[i-1], 'paySum', _incomePay)

        // 应纳税金额写入到表格
        this.$set(this.resultObj?.sumupListData[i-1], 'needTaxSum', +_needPayAccount)
        console.log(`累计应纳税-${i}月：`, +_needPayAccount)

        if (+_needPayAccount > 0) {
          // 对应税率
          let _targetRate = this.getTargetRate(+_needPayAccount)

          // 对应纳税金额
          let _targetTax = this.getTargetTax(i, +_needPayAccount, _targetRate)
          this.resultObj.taxPaySum += +_targetTax
          this.resultObj.taxPaySumupList.push(+_targetTax)

          // 纳税金额写入到表格
          this.$set(this.resultObj.sumupListData[i-1], 'tax', +_targetTax)
          // 累计纳税金额写入到表格
          this.$set(this.resultObj.sumupListData[i-1], 'taxSum', this.resultObj.taxPaySum.toFixed(2))

          // 到手金额计算
          const _curTarget = this.resultObj.sumupListData[i-1]
          const _cash = +_curTarget.pay - + +_curTarget.deductBonus - +_curTarget.tax
          this.$set(this.resultObj.sumupListData[i-1], 'cash', _cash.toFixed(2))

          this.resultObj.cashSum += +_cash
        } else {
          console.warn('你还没有达到交税标准')
        }
      }
    },
    /**
     * m: 月份
     * return: 累计收入
     */
    sumupIncome (m) {
      let _sumIn = +(+this.form.pay * +m).toFixed(2)
      let _sumExt = 0
      for (let e = 0; e < this.form.extData.length; e++) {
        if (e < m) {
          const _targetExt = +this.form.extData[e]
          if (_targetExt > 0) {
            _sumExt += _targetExt
          } else {
            _sumExt -= Math.abs(_targetExt)
          }
        }
      }
      if (+_sumExt > 0) {
        _sumIn += +_sumExt
      } else {
        _sumIn -= Math.abs(+_sumExt)
      }

      console.log(`累计收入-${m}月：`, _sumIn)
      console.log(`累计额外总数-${m}月：`, _sumExt)
      return _sumIn
    },
    /**
     * m: 月份
     * return: 累计免税收入
     */
    deductIncome (m) {
      let _deduct = 0
      this.resultObj.sumupListData.forEach(v => {
        if (+m >= +v.month) {
          _deduct += +v.all
        }
      })
      console.log(`累计免税收入-${m}月: `, +_deduct.toFixed(2))
      return +_deduct.toFixed(2)
    },
    /**
     * num: 累计预扣预缴应纳税所得额
     * return: {} // 对应税率
     */
    getTargetRate (num) {
      let _targetRate = null
      for (let r = 0; r < this.taxRate.length; r++) {
        if (+num <= this.taxRate[r].max) {
          _targetRate = this.taxRate[r]
          break
        }
      }
      console.log('目标税率：', _targetRate)
      return _targetRate
    },
    /**
     * month: 对应月份
     * num: 累计预扣预缴应纳税所得额
     * rate: 对应税率
     * return 对应纳税金额
     * 本期应预扣预缴税额 = （累计预扣预缴应纳税所得额 * 税率 - 速算扣除数）- 累计已预扣预缴税额
     */
    getTargetTax (month, num, rate) {
      const _num = (+num * +rate.rate / 100 - +rate.deduct) - +this.resultObj.taxPaySum
      console.log(`本期应预扣预缴税-${month}月：`, _num.toFixed(2))
      return _num.toFixed(2)
    },
    /**
     * 扣税减免-专项附加
     * m: 月份
     * _curM: 当前月份数据对象
     * return：curM 当月数据对象 curMSum 当月五险一金总额
     */
    taxDeductSpec (m, _curM) {
      // tip: 当前未提前扣税-选的缴费方式不对，先置为0-以后选公司提前缴纳专项附加扣减
      let _curMSum = 0
      const _spec = this.form.deductSpec
      const _items = Object.keys(_spec)
      _items.forEach(k => {
        if (this.form.deductSpecIn) {
          _curM[k] = _spec[k].start <= m ? _spec[k].deduct : 0
        } else {
          _curM[k] = 0
        }
        _curMSum += +_curM[k]
      })
      _curM.deductSpec = _curMSum.toFixed(2)
      console.log(`专项附加-${m}月：`, _curMSum)
      return { curMSpec: _curM, curMSumSpec: _curMSum }
    },
    /**
     * 扣税减免-五险一金
     * m: 月份
     * _curM: 当前月份数据对象
     * return：curM 当月数据对象 curMSum 当月五险一金总额
     */
    taxDeductBonus (m, _curM) {
      let _curMSum = 0
      const _keys = ['unemploy', 'medical', 'retired', 'gjj']
      _keys.forEach(k => {
        _curM[k] = this.getBonusMonthItem(k, m)
        _curMSum += +_curM[k]
      })
      _curM.deductBonus = _curMSum.toFixed(2)
      console.log(`五险一金-${m}月：`, _curMSum)
      return { curMBonus: _curM, curMSumBonus: _curMSum }
    },
    /**
     * 获取社保(五险一金)单项月缴存额
     * key: 单项key
     * m: 月份
     * return 单项缴存额
     */
    getBonusMonthItem (key, m) {
      const _tg = this.form.deductBonus
      const _bs = +m > 6 ? 
        (+m < 10 ? (_tg[key].tBase || _tg[key].sBase) :
        _tg[key].sBase) :
        _tg[key].fBase
      return (_tg[key].rate * _bs / 100).toFixed(2)
    }
  }
}
</script>
<style lang="less" scoped>
section {
  min-height: 100vh;
  /deep/ .tax-table {
    width: 100%;
    .weight {
      font-weight: bolder;
    }
  }
  .tax-wrap {   
    padding: 10px;
    .tax-form {
      padding-right: 40px;
    }
    .tax-result {
      .desc {
        line-height: 18px;
        margin: 8px;
      }
    }
  }
}
</style>
